package org.javahispano.javacup.tacticas.tacticas_aceptadas.TacticaMagallanes;

import java.awt.Color;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.EstiloUniforme;
import org.javahispano.javacup.modelo.JugadorDetalle;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;
import org.javahispano.javacup.modelo.Tactica;
import org.javahispano.javacup.modelo.TacticaDetalle;



public class TacticaMagallanes implements Tactica {
	
	public abstract class  DSL{
		private SituacionPartido sp;
		private int player;
		public DSL(SituacionPartido sp, Integer player){
			this.sp=sp;
			this.player=player;
		}
		public Posicion arcoRival(){return Constantes.centroArcoSup;}
		public Posicion posicionBalon(){return sp.balon();}
		public Posicion arcoPropio(){return Constantes.centroArcoInf;}
		public Posicion media(Posicion p1, Posicion p2){return Posicion.media(p1,p2);}
		public double getX(Posicion p){ return p.getX();}
		public double getY(Posicion p){ return p.getY();}
		public abstract Posicion resolve();
		public Posicion posicionJugador() {return sp.misJugadores()[player];}
		public Posicion propio(int i) {return sp.misJugadores()[i];}
		public Posicion rival(int i) {return sp.rivales()[i];}
		public int me() {return player;}
		public  Posicion alterarPosicion(Posicion pos, double i,double adelantoPase) {
			return new Posicion(pos.getX()+i,pos.getX()+adelantoPase);
		}
	}
	
	public class DSLAtaque extends DSL{
		public DSLAtaque(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return media(arcoRival(),posicionBalon());
		}
	}
	
	public class DSLDefensa extends DSL{
		DSLDefensa(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			Posicion p=null;
			 p=(((0 < (getX(arcoPropio()))))) ?
				  	 (arcoPropio()) 
				  :((media((media(arcoRival(),(media((media(arcoPropio(),arcoRival())),posicionBalon())))),arcoRival()))); 
			
			return p;
		}
	}
	
	public class DSLAtaque2 extends DSL{
		public DSLAtaque2(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return media(arcoRival(),posicionBalon());
		}
	}
	 

	public class DSLDefensa2 extends DSL{
		public DSLDefensa2(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			Posicion p=null;
			 p=(((0 < (getX(arcoPropio()))))) ?
				  	 (arcoPropio()) 
				  :((media((media(arcoRival(),(media((media(arcoPropio(),arcoRival())),posicionBalon())))),arcoRival()))); 
			
			return media(arcoRival(),arcoPropio());
		}
	}
	
	public class DSLPase2 extends DSL{
		public DSLPase2(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return alterarPosicion(propio(me()+2),0,adelantoPase);
		}
	}
	/*
	inc((inc(2))) ==> 27 ==> 14 ==> 1.0 ==> 85 ==> 4 ==> 4 ==> 
	posicionBalon() ==> 
	media(arcoRival(),posicionBalon()) ==> 
	propio( 6)
	 */
	public class DSLDefensa3 extends DSL{
		public DSLDefensa3(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return posicionBalon();
		}
	}
	
	public class DSLAtaque3 extends DSL{
		public DSLAtaque3(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return media(arcoRival(),posicionBalon());
		}
	}
	
	public class DSLPase3 extends DSL{
		public DSLPase3(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return propio( 6);
		}
	}
	
	public class DSLPase4 extends DSL{
		public DSLPase4(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return alterarPosicion((propio( 2)),-2.4532437324523926,(getX((rival( me())))));
		}
		
	}
	public class DSLDefensa4 extends DSL{
		public DSLDefensa4(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return posicionJugador();
		}
	}
	
	public class DSLAtaque4 extends DSL{
		public DSLAtaque4(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return media((media(posicionBalon(),posicionJugador())),((((0 >= 0))) ? (arcoRival()) :(posicionBalon())));
		}
	}

	public class DSLPase5 extends DSL{
		public DSLPase5(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return  alterarPosicion((propio( 5)),11.667728424072266,(getX((rival( me())))));

			//alterarPosicion((propio( 2)),-2.4532437324523926,(getX((rival( me())))));
		}
		
	}
	public class DSLDefensa5 extends DSL{
		public DSLDefensa5(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return posicionJugador();
		}
	}
	
	public class DSLAtaque5 extends DSL{
		public DSLAtaque5(SituacionPartido sp, Integer player){
			super(sp,player);
		}
		public Posicion resolve(){
			return
			media((media(posicionBalon(),posicionJugador())),((((0 >= 0))) ? (arcoRival()) :((media(posicionBalon(),posicionJugador()))))); 
			//media((media(posicionBalon(),posicionJugador())),((((0 >= 0))) ? (arcoRival()) :(posicionBalon())));
		}
	}
	

	
	public DSL instanciarDSL(TacticaMagallanes t,String dsl,SituacionPartido sp, Integer player){
		DSL instance=null;
		
		try {
			instance=(DSL)Class.forName(
					"org.javahispano.javacup.tacticas.tacticas_aceptadas.TacticaMagallanes.TacticaMagallanes$"+dsl).getConstructor(TacticaMagallanes.class,SituacionPartido.class,Integer.class).newInstance(t,sp,player);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return instance;
	}
	
	private int[] delanteros = new int[] { 8, 9, 10 };
	private int[] defensas = new int[] { 1, 2, 3 };
	
	private int maxrecuperadores = 3;
	private int adelantoPase = 30;
	private int adelantoPaseMiddle = 15;

	private int distanciaDisparo = 30;
	private double fuerzaDisparo = 1;

	private int costoLejania = 50;
	private int costoRivales = 5;
	private int costoAtaqueRivales = 5;
	
	private String dslDefensa="DSLDefensa2";
	private String dslAtaque="DSLAtaque2";
	private String dslPase="DSLPase3";
	
	public TacticaMagallanes() {
		/*
		 * 6;45;49;1.0;63;7;6
		 * 3,30,15,30,1,50,5,5
		 *  inc((inc((inc((inc(2))))))) ==> 
		 *  dec((inc((inc((inc(14))))))) ==> 
		 *  inc(28) ==> 
		 *  1.0 ==> 
		 *  dec((dec((inc((inc(32))))))) ==> 
		 *  dec((dec((inc((dec(9))))))) ==> 
		 *  inc((inc((inc((inc(3)))))))
		 */
		//inc(2) ==> 21 ==> 47 ==> 1.0 ==> 46 ==> 6 ==> inc(7) ==> 
				//this(3,21,47,1.0,46,6,8);
		//inc(1) ==> 28 ==> 34 ==> 1.0 ==> 27 ==> 3 ==> dec(9) 
		//inc((inc(2))) ==> 27 ==> 14 ==> 1.0 ==> 85 ==> 4 ==> 4 ==>
			//	this(2,28,34,1.0,27,3,8,"DSLDefensa2","DSLAtaque2","DSLPase2");
				//this(3,27,14,1.0,85,4,4,"DSLDefensa3","DSLAtaque3","DSLPase3");
				//this(1,21,13,1.0,24,2,9,"DSLDefensa4","DSLAtaque4","DSLPase4");
		/* 
		 * inc((dec((inc(2))))) ==> 
			
			inc((inc((inc((inc(37))))))) ==> 
		
		inc((dec((inc((dec(39))))))) ==> 
		1.0 ==> 
		dec((dec((dec((dec((dec((dec((dec(90))))))))))))) 
		==> 7
		 ==> dec(2)
		*/
				this(6,45,49,1.0,63,7,6,"DSLDefensa3","DSLAtaque3","DSLPase3");
				//this(3,41,39,1.0,83,7,1,"DSLDefensa5","DSLAtaque5","DSLPase5");
			}

			public TacticaMagallanes(int maxrecuperadores, int adelantoPase,
					int distanciaDisparo, double fuerzaDisparo, int costoLejania,
					int costoRivales, int costoAtaqueRivales, String defensa,String ataque,String pase ) {
				this.maxrecuperadores=maxrecuperadores;
				this.adelantoPase=adelantoPase;
				this.adelantoPaseMiddle = (adelantoPase / 2);
				this.distanciaDisparo=distanciaDisparo;
				this.fuerzaDisparo=fuerzaDisparo;
				this.costoLejania=costoLejania;
				this.costoRivales=costoRivales;
				this.costoAtaqueRivales=costoAtaqueRivales;
				this.dslAtaque=ataque;
				this.dslDefensa=defensa;
				this.dslPase=pase;


			}
	

	Posicion alineacion1[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-19.46564885496183, -31.6044776119403),
			new Posicion(0.2595419847328244, -31.082089552238806),
			new Posicion(19.984732824427482, -31.6044776119403),
			new Posicion(7.526717557251908, -11.753731343283583),
			new Posicion(-8.564885496183205, -11.753731343283583),
			new Posicion(-24.65648854961832, -2.3507462686567164),
			new Posicion(23.099236641221374, -2.873134328358209),
			new Posicion(-14.274809160305344, 30.559701492537314),
			new Posicion(-0.7786259541984732, 29.097014925373134),
			new Posicion(12.717557251908397, 29.51492537313433) };

	Posicion alineacion2[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -31.082089552238806),
			new Posicion(11.16030534351145, -31.6044776119403),
			new Posicion(27.251908396946565, -27.94776119402985),
			new Posicion(-29.84732824427481, -26.902985074626866),
			new Posicion(8.564885496183205, -7.574626865671642),
			new Posicion(-10.641221374045802, -7.052238805970149),
			new Posicion(27.251908396946565, 4.440298507462686),
			new Posicion(-29.32824427480916, 3.3955223880597014),
			new Posicion(-0.2595419847328244, 19.067164179104477),
			new Posicion(-0.2595419847328244, 35.78358208955224) };

	Posicion alineacion3[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -31.082089552238806),
			new Posicion(11.16030534351145, -31.6044776119403),
			new Posicion(26.732824427480914, -20.111940298507463),
			new Posicion(-29.32824427480916, -21.67910447761194),
			new Posicion(0.2595419847328244, -0.26119402985074625),
			new Posicion(-18.946564885496183, -0.26119402985074625),
			new Posicion(18.946564885496183, -0.26119402985074625),
			new Posicion(-19.46564885496183, 35.78358208955224),
			new Posicion(-0.2595419847328244, 19.067164179104477),
			new Posicion(18.946564885496183, 35.26119402985075) };

	Posicion alineacion4[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -31.082089552238806),
			new Posicion(11.16030534351145, -31.6044776119403),
			new Posicion(28.290076335877863, -28.470149253731343),
			new Posicion(-28.290076335877863, -28.470149253731343),
			new Posicion(11.16030534351145, -1.3059701492537314),
			new Posicion(-10.641221374045802, -0.7835820895522387),
			new Posicion(-27.251908396946565, 31.6044776119403),
			new Posicion(-10.641221374045802, 30.559701492537314),
			new Posicion(9.603053435114505, 28.992537313432837),
			new Posicion(25.69465648854962, 28.992537313432837) };

	Posicion alineacion5[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -35.78358208955224),
			new Posicion(12.717557251908397, -35.26119402985075),
			new Posicion(28.290076335877863, -28.470149253731343),
			new Posicion(-28.290076335877863, -28.470149253731343),
			new Posicion(14.793893129770993, -18.544776119402986),
			new Posicion(-17.389312977099234, -19.58955223880597),
			new Posicion(-23.618320610687025, -0.7835820895522387),
			new Posicion(5.969465648854961, -5.485074626865671),
			new Posicion(0.2595419847328244, -0.26119402985074625),
			new Posicion(22.580152671755727, -1.3059701492537314) };

	Posicion alineacion6[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -35.78358208955224),
			new Posicion(12.717557251908397, -35.26119402985075),
			new Posicion(28.290076335877863, -28.470149253731343),
			new Posicion(-28.290076335877863, -28.470149253731343),
			new Posicion(14.793893129770993, -18.544776119402986),
			new Posicion(-17.389312977099234, -19.58955223880597),
			new Posicion(-23.618320610687025, -0.7835820895522387),
			new Posicion(6.4885496183206115, -6.529850746268657),
			new Posicion(-6.4885496183206115, -6.529850746268657),
			new Posicion(22.580152671755727, -1.3059701492537314) };

	class TacticaDetalleImpl implements TacticaDetalle {

		public String getNombre() {
			return "Republica Independiente de Magallanes";
		}

		public String getPais() {
			return "Chile";
		}

		public String getEntrenador() {
			return "Mauricio N��ez";
		}

		public Color getColorCamiseta() {
			return new Color(255, 0, 0);
		}

		public Color getColorPantalon() {
			return new Color(0, 0, 255);
		}

		public Color getColorFranja() {
			return new Color(37, 139, 109);
		}

		public Color getColorCalcetas() {
			return new Color(255, 255, 255);
		}

		public Color getColorPortero() {
			return new Color(115, 86, 236);
		}

		public EstiloUniforme getEstilo() {
			return EstiloUniforme.SIN_ESTILO;
		}

		public Color getColorCamiseta2() {
			return new Color(101, 89, 147);
		}

		public Color getColorPantalon2() {
			return new Color(182, 126, 41);
		}

		public Color getColorFranja2() {
			return new Color(74, 47, 38);
		}

		public Color getColorCalcetas2() {
			return new Color(85, 22, 111);
		}

		public Color getColorPortero2() {
			return new Color(91, 55, 68);
		}

		public EstiloUniforme getEstilo2() {
			return EstiloUniforme.FRANJA_DIAGONAL;
		}

		class JugadorImpl implements JugadorDetalle {

			String nombre;
			int numero;
			Color piel, pelo;
			double velocidad, remate, presicion;
			boolean portero;
			Posicion posicion;

			public JugadorImpl(String nombre, int numero, Color piel,
					Color pelo, double velocidad, double remate,
					double presicion, boolean portero) {
				this.nombre = nombre;
				this.numero = numero;
				this.piel = piel;
				this.pelo = pelo;
				this.velocidad = velocidad;
				this.remate = remate;
				this.presicion = presicion;
				this.portero = portero;
			}

			public String getNombre() {
				return nombre;
			}

			public Color getColorPiel() {
				return piel;
			}

			public Color getColorPelo() {
				return pelo;
			}

			public int getNumero() {
				return numero;
			}

			public boolean esPortero() {
				return portero;
			}

			public double getVelocidad() {
				return velocidad;
			}

			public double getRemate() {
				return remate;
			}

			public double getPresicion() {
				return presicion;
			}

		}

		public JugadorDetalle[] getJugadores() {
			return new JugadorDetalle[] {
					new JugadorImpl("Christofer", 1, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 1.0d, 1.0d, true),
					new JugadorImpl("Ruben", 2, new Color(0, 0, 0), new Color(
							0, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Gabriel", 3, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Gari", 4, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Miguel", 5, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Hugo", 6, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Mark", 7, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Mauricio", 8, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.53d, 0.78d, false),
					new JugadorImpl("Humberto", 9, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 1.0d, 1.0d, false),
					new JugadorImpl("Mago", 10, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 0.5d, 0.81d, false),
					new JugadorImpl("Alexis", 11, new Color(255, 200, 150),
							new Color(50, 0, 0), 1.0d, 1.0d, 1.0d, false) };
		}
	}

	TacticaDetalle detalle = new TacticaDetalleImpl();

	public TacticaDetalle getDetalle() {
		return detalle;
	}

	public Posicion[] getPosicionSaca(SituacionPartido sp) {
		return alineacion5;
	}

	public Posicion[] getPosicionRecive(SituacionPartido sp) {
		return alineacion6;
	}

	private Engine engine = new Engine();
	private Random r = new Random();

	class Engine {
		private SituacionPartido sp;

		private Engine() {

		}

		public void actualizarEstado(SituacionPartido sp) {
			this.sp = sp;
		}

		public double evaluar(Posicion posicion) {
			Posicion[] rivales = sp.rivales();
			Posicion[] amigos = sp.misJugadores();

			double cost = 0;
			double min = posicion.norma(rivales[0]) + costoAtaqueRivales
					* rivales[0].getY();
			for (int i = 0; i < rivales.length; i++) {
				double c = posicion.norma(rivales[i]) + costoAtaqueRivales
						* rivales[i].getY();
				if (c < min) {
					min = c;
				}
			}
			cost = min * -costoRivales;
			cost += (costoLejania * Constantes.penalSup.norma(posicion));
			return cost;
		}

		public Posicion getBestPase(Posicion origen, Posicion[] alts) {
			int[] idx = origen.indicesMasCercanos(alts);
			Posicion retorno = alts[idx[0]];
			double eval = evaluar(retorno);
			for (int i = 1; i < idx.length; i++) {
				// if(i>6)break;
				Posicion candidate = alts[idx[i]];
				double candidateEval = evaluar(candidate);
				if (eval > candidateEval) {
					eval = candidateEval;
					retorno = candidate;
				}
			}

			return retorno;
		}
		
		

		public Cmd paseDirecto(int i, int j) {
			Posicion destino = sp.misJugadores()[j];
			return new Pase(i, destino, false);
		}

		public Cmd poner(int i) {
			DSL dsl=instanciarDSL(TacticaMagallanes.this, dslPase, sp, i);
			Posicion destino=dsl.resolve();
			return new Pase(i, destino, true);
		}

		class Movimientos{
			
			Posicion actual=null;
			Posicion balon=null;
			int i=0;
			Posicion retorno=null;
			
			Posicion arco=Constantes.centroArcoInf;
			Posicion arcoRival=Constantes.centroArcoSup;
			
			public Posicion[] yuxta(Posicion p1,Posicion p2){
				return null;
			}
			
			public Posicion avance(Posicion p1, Posicion p2){
				return null;
			}
			public Posicion media(Posicion p1, Posicion p2){
				return Posicion.media(p1, p2);
			}
			
			public double norma(Posicion p1,Posicion p2){
				return p1.norma(p2);
			}
			
			public double distancia(Posicion p1,Posicion p2){
				return p1.norma(p2);
			}

			
			public Posicion balon(){
				return null;
			}
			
			public Posicion actual(){
				return null;
			}
			
			public Posicion alineacion(){
				return null;
			}
			

			
		}
		
		public Cmd bestPosicion(int i) {
			Object[] a_data=new Object[]{sp,i};
			Posicion media = Posicion.media(sp.balon(),
					Constantes.centroArcoInf);
			Posicion centro = Posicion.media(
					new Posicion(0, sp.balon().getY()),
					Constantes.centroArcoSup);
			
			if (inside(i,defensas) && sp.balon().getY() < -35 && r.nextBoolean())
			{
				Posicion destino = null;
				
				
				DSL f=instanciarDSL(TacticaMagallanes.this,dslDefensa, sp, i);
				//new DSLDefensa2(sp,i);
				destino=f.resolve();
	
						  
					
					
					return new Ir(i, destino);

			}
				
			if (inside(i,delanteros) && sp.balon().getY() < 30 && sp.balon().getY() > -60)
			{
				
				Posicion destino = null;
				//DSL f=new DSLAtaque2(sp,i);
				DSL f=instanciarDSL(TacticaMagallanes.this,dslAtaque, sp, i);
				
				destino=f.resolve();
				return new Ir(i, destino);
			}
			return new Ir(i, alineacion1[i]);
		}
		
			

		public Cmd dispararArco(int i) {
			return new Shoot(i);
		}
		
		public Cmd correr(int i){
			return new Run(i);
		}

		public double tiempoLlegada(Posicion origen,Posicion destino, double vel){
			
			double tiempo = origen.distancia(destino)/vel;
			return tiempo;
		}
		

		
		public Cmd bestPase(int i) {

			Posicion[] destinos = sp.misJugadores();
			
			Posicion[] alternativas = null;
			List<Posicion> alt = new ArrayList<Posicion>();

			for (int ii = 1; ii < 11; ii++) {
				if (ii != i) {
					alt.add(destinos[ii]);
				}
				alt.add(new Posicion(destinos[ii].getX()
						+ r.nextInt(adelantoPase) - adelantoPaseMiddle,
						destinos[ii].getY() + r.nextInt(adelantoPaseMiddle)));
				alt.add(new Posicion(destinos[ii].getX()
						+ r.nextInt(adelantoPase) - adelantoPaseMiddle,
						destinos[ii].getY() + r.nextInt(adelantoPaseMiddle)));
				alt.add(new Posicion(destinos[ii].getX()
						+ r.nextInt(adelantoPase) - adelantoPaseMiddle,
						destinos[ii].getY() + r.nextInt(adelantoPaseMiddle)));
			}
			alternativas = alt.toArray(new Posicion[alt.size()]);

			Posicion destino = getBestPase(destinos[i], alternativas);
			if (destinos[i].distancia(destino) > 15)
				return new Pase(i, destino, true);
			return new Pase(i, destino, false);
		}

	}

	abstract class Cmd {
		private Engine engine;
		public Cmd(Engine engine){
			this.engine=engine;
		}
		public abstract void visit(List<Comando> cmd);
		public abstract double evaluate();
	}

	class Nop extends Cmd {
		public Nop(){
			super(engine);
		}
		public void visit(List<Comando> cmd) {

		}

		public double evaluate() {
			return 0;
		}
	}

	class Ir extends Cmd {
		private int i;
		private Posicion pos;

		private Ir(int i, Posicion pos) {
			super(engine);
			this.i = i;
			this.pos = pos;
		}

		public void visit(List<Comando> cmd) {
			
			cmd.add(new ComandoIrA(i, pos));
		}

		public double evaluate() {
			double cost=15-engine.sp.misJugadores()[i].distancia(pos);
			return cost;
		}
	}

	class Run extends Cmd {
		private int i;

		private Run(int i) {
			super(engine);
			this.i = i;
		}

		public void visit(List<Comando> cmd) {
			cmd.add(new ComandoGolpearBalon(i));
		}

		public double evaluate() {
			double cost=15*engine.sp.getVelocidadJugador(i);
			return cost;
		}
	}

	class Shoot extends Cmd {
		private int i;

		Shoot(int i) {
			super(engine);
			this.i = i;
		}

		public void visit(List<Comando> cmd) {
			Comando comando = null;
			Random r = new Random();
			if (r.nextBoolean()) {
				// Ordena que debe rematar al centro del arco
				comando = new ComandoGolpearBalon(i, Constantes.centroArcoSup,
						fuerzaDisparo, 12 + r.nextInt(6));
			} else if (r.nextBoolean()) {
				// Ordena que debe rematar al poste derecho
				comando = new ComandoGolpearBalon(i,
						Constantes.posteDerArcoSup, fuerzaDisparo,
						12 + r.nextInt(6));
			} else {
				// Ordena que debe rematar al poste izquierdo
				comando = new ComandoGolpearBalon(i,
						Constantes.posteIzqArcoSup, fuerzaDisparo,
						12 + r.nextInt(6));
			}
			cmd.add(comando);
		}

		public double evaluate() {
			double cost=45-engine.sp.misJugadores()[i].distancia(Constantes.centroArcoSup);
			return cost;
		}
	}

	class Pase extends Cmd {
		private int i;
		private Posicion destino;
		private boolean alto;

		private Pase(int i, Posicion destino, boolean alto) {
			super(engine);
			this.i = i;
			this.destino = destino;
			this.alto = alto;
		}

		public void visit(List<Comando> cmd) {
			Comando comando = new ComandoGolpearBalon(i, destino, 1, alto);
			cmd.add(comando);
		}

		public double evaluate() {
			double cost=15*engine.sp.getRemateJugador(i)-25*engine.sp.getErrorJugador(i);
			return cost;
		}
	}

	class Combinacion extends Cmd {
		private List<Cmd> childs;
		private int age;

		private Combinacion(List<Cmd> childs, int age) {
			super(engine);
			this.childs = childs;
			this.age = age;
		}

		public void visit(List<Comando> cmd) {
			age--;
			for (Cmd child : childs) {
				child.visit(cmd);
			}
		}

		public double evaluate() {
			return 0;
		}

		public int getAge() {
			return age;
		}
	}

	public boolean inside(int i, int j[]) {
		boolean inside = false;
		for (int jj : j) {
			if (i == jj) {
				inside = true;
				break;
			}
		}
		return inside;
	}

	public List<Comando> ejecutar(SituacionPartido sp) {
		
		List<Cmd> comandosAll = new ArrayList<Cmd>();
		List<Comando> retorno = new ArrayList<Comando>();
		engine.actualizarEstado(sp);
		int[] recuperadores = sp.getRecuperacionBalon();

		int cuantos = recuperadores.length < maxrecuperadores ? recuperadores.length
				: maxrecuperadores;

		for (int player = 0; player < 11; player++) {
			

			
			List<Cmd> comandos = new ArrayList<Cmd>();
			comandos.add(engine.bestPosicion(player));
			if (recuperadores.length > 1) {
				int[] rec = new int[cuantos-1];
				System.arraycopy(recuperadores,1,rec,0,cuantos-1);
				double[] posRecuperacion = sp.getTrayectoria(recuperadores[0]);
				if (!sp.sacaRival() && inside(player, rec)) {
					comandos.add(new Ir(player, new Posicion(
							posRecuperacion[0], posRecuperacion[1])));
				}
			}

			if (inside(player, sp.puedenRematar())) {
				comandos.add(engine.bestPase(player));
				if (inside(player, defensas)) {
					comandos.add(engine.poner(player));
				}
				if (inside(player, delanteros)) {
					comandos.add(engine.bestPase(player));
					if (sp.misJugadores()[player]
							.distancia(Constantes.penalSup) <= distanciaDisparo
							|| r.nextBoolean()) {
						comandos.add(engine.dispararArco(player));
					} else {
						if (r.nextInt(100) < 50) {
							comandos.add(engine.correr(player));
						}
					}
				}
			}
			comandosAll.addAll((comandos));

		}

		for (Cmd cmd : comandosAll) {
			cmd.visit(retorno);
		}
		return retorno;
	}
	
}
